package com.jlf.tool.toolkit;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * 类型相关的辅助工具
 *
 * @author wujr
 * 2023/8/7
 * @version 1.0
 * 【变更历史】
 * [wujr 2023/8/7 1.0 新增]
 */
public class TypeToolkit {
    public static Class<?> resolveTypeClass(Type type){
        if (type instanceof Class){
            return (Class<?>)type;
        }else if (type instanceof ParameterizedType){
            ParameterizedType t = (ParameterizedType)type;
            Type[] subs = t.getActualTypeArguments();
            return resolveTypeClass(subs[subs.length - 1]);
        }else{
            return type.getClass();
        }
    }
    public static Class<?> resolveRawType(Type type){
        if (type instanceof Class){
            return (Class<?>)type;
        }else if (type instanceof ParameterizedType){
            ParameterizedType t = (ParameterizedType)type;
            Type rawType = t.getRawType();
            if (!(rawType instanceof Class)){
                return rawType.getClass();
            }
            Class<?> c = (Class<?>)rawType;
            return checkRawType(c);
        }else{
            return type.getClass();
        }
    }
    public static Class<?> checkRawType(Class<?> objectClass){
        Class<?>[] collectionClass = {List.class, Set.class, Map.class};
        Class<?>[] defaultClass = {ArrayList.class, HashSet.class, HashMap.class};
        for (int index = 0; index < collectionClass.length; ++ index){
            Class<?> clz = checkAssignable(collectionClass[index], objectClass, defaultClass[index]);
            if (clz != null){
                return clz;
            }
        }
        return objectClass;
    }
    public static Class<?> checkAssignable(Class<?> collectionClass, Class<?> objectClass, Class<?> def){
        if (collectionClass.isAssignableFrom(objectClass)){
            if (objectClass.isAssignableFrom(collectionClass)){
                return def;
            }else{
                return objectClass;
            }
        }
        return null;
    }
}
